﻿using System.Collections.Generic;

namespace DatabaseGroup.SSIS.SourceAdapters.Parser
{
    /// <summary>
    /// Processes incoming characters and attempts to match them to an expected state
    /// </summary>
    internal class ParsingState : IParsingState
    {
        private readonly List<IParsingState> _nextStates = new List<IParsingState>();

        #region IParsingState Members

        /// <summary>
        /// Add a state to expect when processing
        /// </summary>
        /// <param name="parsingState">The state to expect</param>
        public void AddNextState(IParsingState parsingState)
        {
            ArgumentVerifier.CheckObjectArgument(parsingState, "parsingState");

            _nextStates.Add(parsingState);
        }

        /// <summary>
        /// (Stubbed) Set the current error state
        /// </summary>
        /// <param name="errorState">The error state to set</param>
        public void SetErrorState(IParsingState errorState)
        {
        }

        /// <summary>
        /// Using the parsing context attempts to process an incoming character
        /// and see if the result meets an expected state
        /// </summary>
        /// <param name="context">The parsing state to use</param>
        /// <param name="nextChar">The incoming character</param>
        /// <returns>The result of parsing the char</returns>
        public ParsingResult ProcessCharacter(IParsingContext context, char nextChar)
        {
            ArgumentVerifier.CheckObjectArgument(context, "context");

            foreach (IParsingState parsingState in _nextStates)
            {
                ParsingResult result = parsingState.ProcessCharacter(context, nextChar);
                
                // If the char didn't meets the current state in the loop
                // continue looking for a state it does match
                if (result == ParsingResult.Miss) 
                    continue;
                
                if (context.CurrentState == this)
                {
                    // If the current state has not changed in the ProcessCharacter call,
                    // we should change it now.
                    context.CurrentState = parsingState;
                }
                return result;
            }

            // char didn't meet any of the expected states so return as a "standard" match
            context.Append(nextChar);
            return ParsingResult.Match;
        }

        #endregion
    }
}
